#include "cameradebug.h"
#include "application.h"
#include "inputs/manager.h"


namespace infinity {


CameraDebug::CameraDebug()
{
	m_cameraNode.setPosition(dw::maths::Point3f(20.0f, 20.0f, 0.0f));

	const dw::system::Window& window = Application::getInstance().getWindow();
	m_camera.setAspectRatio( (dw::float32)window.getWidth() / (dw::float32)window.getHeight() );

	m_cameraSpeed  = 20.0f;

	m_cameraSpeedUp.addCondition(dw::inputs::KeyStateCondition(OIS::KC_ADD, dw::inputs::ButtonStateCondition::Pressed));
	m_cameraSpeedDown.addCondition(dw::inputs::KeyStateCondition(OIS::KC_SUBTRACT, dw::inputs::ButtonStateCondition::Pressed));

	m_flyForward.addCondition(dw::inputs::KeyStateCondition(OIS::KC_UP, dw::inputs::ButtonStateCondition::Down));
	m_flyBackward.addCondition(dw::inputs::KeyStateCondition(OIS::KC_DOWN, dw::inputs::ButtonStateCondition::Down));

	m_flyLeft.addCondition(dw::inputs::KeyStateCondition(OIS::KC_LEFT, dw::inputs::ButtonStateCondition::Down));
	m_flyRight.addCondition(dw::inputs::KeyStateCondition(OIS::KC_RIGHT, dw::inputs::ButtonStateCondition::Down));

	m_mousePan.addCondition(dw::inputs::MouseButtonCondition(OIS::MB_Right, dw::inputs::ButtonStateCondition::Down));
	m_mousePan.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::X, dw::inputs::MouseCursorSampler::Relative));
	m_mousePan.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::Y, dw::inputs::MouseCursorSampler::Relative));

	m_mouseRotate.addCondition(dw::inputs::KeyStateCondition(OIS::KC_ESCAPE, dw::inputs::ButtonStateCondition::Up));
	m_mouseRotate.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::X, dw::inputs::MouseCursorSampler::Relative));
	m_mouseRotate.addSampler(dw::inputs::MouseCursorSampler(dw::inputs::MouseCursorSampler::Y, dw::inputs::MouseCursorSampler::Relative));

	//m_resetCamera.addCondition(KeyStateCondition(OIS::KC_HOME, ButtonStateCondition::Down));
}

CameraDebug::~CameraDebug()
{
	;
}


/*virtual*/ void CameraDebug::update(dw::float32 deltaT)
{
	bool cameraNeedsFix = false;

	if (m_cameraSpeedUp.isActive())
	{
		m_cameraSpeed = std::min(100.0f, m_cameraSpeed + 5.0f);
	}
	if (m_cameraSpeedDown.isActive())
	{
		m_cameraSpeed = std::max(10.0f, m_cameraSpeed - 5.0f);
	}
	if (m_flyForward.isActive())
	{
		Vector3f cameraPos(m_cameraNode.getTransform().pos);

		cameraPos += m_cameraSpeed * deltaT * Vector3f(m_cameraNode.getTransform().at);

		m_cameraNode.setPosition(dw::maths::Point3f(cameraPos.x, cameraPos.y, cameraPos.z));
	}
	if (m_flyBackward.isActive())
	{
		Vector3f cameraPos(m_cameraNode.getTransform().pos);

		cameraPos -= m_cameraSpeed * deltaT * Vector3f(m_cameraNode.getTransform().at);

		m_cameraNode.setPosition(dw::maths::Point3f(cameraPos.x, cameraPos.y, cameraPos.z));
	}
	if (m_flyLeft.isActive())
	{
		Vector3f cameraPos(m_cameraNode.getTransform().pos);

		cameraPos += m_cameraSpeed * deltaT * Vector3f(m_cameraNode.getTransform().right);

		m_cameraNode.setPosition(dw::maths::Point3f(cameraPos.x, cameraPos.y, cameraPos.z));
	}
	if (m_flyRight.isActive())
	{
		Vector3f cameraPos(m_cameraNode.getTransform().pos);

		cameraPos -= m_cameraSpeed * deltaT * Vector3f(m_cameraNode.getTransform().right);

		m_cameraNode.setPosition(dw::maths::Point3f(cameraPos.x, cameraPos.y, cameraPos.z));
	}

	if (m_mousePan.isActive())
	{
		Vector3f cameraPos(m_cameraNode.getTransform().pos);

		dw::float32 winSize = (dw::float32)Application::getInstance().getWindow().getHeight();
		dw::float32 valueX = m_mousePan.getValue(0) / winSize;
		dw::float32 valueY = m_mousePan.getValue(1) / winSize;

		cameraPos = cameraPos +
			m_cameraSpeed * valueX * Vector3f(m_cameraNode.getTransform().right) +
			m_cameraSpeed * valueY * Vector3f(m_cameraNode.getTransform().up);

		m_cameraNode.setPosition(dw::maths::Point3f(cameraPos.x, cameraPos.y, cameraPos.z));
	}
	
	if (m_mouseRotate.isActive())
	{
		dw::float32 winSize = (dw::float32)Application::getInstance().getWindow().getHeight();
		dw::float32 valueX = 0.3f * m_mouseRotate.getValue(0) / winSize;
		dw::float32 valueY = 0.3f * m_mouseRotate.getValue(1) / winSize;

		const Matrix4f cameraMtx(m_cameraNode.getTransform());
		const dw::maths::Quaternionf cameraRotY = dw::maths::Quaternionf::fromAxisAngle(Vector3f::unitY,
			dw::maths::pi * -valueX);
		const dw::maths::Quaternionf cameraRotX = dw::maths::Quaternionf::fromAxisAngle(Vector3f::unitX,
			dw::maths::pi * valueY);

		const dw::maths::Matrix3f rotationMtx = (cameraRotY + cameraRotX).toMatrix();

		m_cameraNode.setTransform(Matrix4f(rotationMtx, Vector3f::zero) * cameraMtx);

		cameraNeedsFix = true;
	}

// 	if (m_resetCamera.isActive())
// 	{
// 		m_cameraNode.lookAt(dw::maths::Point3f::zero);
// 
// 		cameraNeedsFix = true;
// 	}

	if (cameraNeedsFix)
	{
		Matrix4f cameraMtx(m_cameraNode.getTransform());

		// Matrix4f cameraMtx(m_physicsObject->getTransform());


		Vector3f right = Vector3f(cameraMtx.right);
		Vector3f up;
		Vector3f at = Vector3f(cameraMtx.at);

		right.y = 0.0f;
		right.normalize();

		up = Vector3f::cross(at, right);
		up.normalize();

		at = Vector3f::cross(right, up);
		at.normalize();

		cameraMtx.right = dw::maths::Vector4f(right);
		cameraMtx.up = dw::maths::Vector4f(up);
		cameraMtx.at = dw::maths::Vector4f(at);

		m_cameraNode.setTransform(cameraMtx);
	}
}

/*virtual*/ void CameraDebug::onRegistered()
{
	dw::inputs::InputManager& inputManager(dw::inputs::InputManager::getInstance());

	inputManager.registerCommand(&m_cameraSpeedUp);
	inputManager.registerCommand(&m_cameraSpeedDown);
	inputManager.registerCommand(&m_flyForward);
	inputManager.registerCommand(&m_flyBackward);
	inputManager.registerCommand(&m_flyLeft);
	inputManager.registerCommand(&m_flyRight);
	inputManager.registerCommand(&m_mousePan);
	inputManager.registerCommand(&m_mouseRotate);
	//inputManager.registerCommand(&m_resetCamera);
}

/*virtual*/ void CameraDebug::onUnRegistered()
{
	dw::inputs::InputManager& inputManager(dw::inputs::InputManager::getInstance());

	inputManager.unregisterCommand(&m_cameraSpeedUp);
	inputManager.unregisterCommand(&m_cameraSpeedDown);
	inputManager.unregisterCommand(&m_flyForward);
	inputManager.unregisterCommand(&m_flyBackward);
	inputManager.unregisterCommand(&m_flyLeft);
	inputManager.unregisterCommand(&m_flyRight);
	inputManager.unregisterCommand(&m_mousePan);
	inputManager.unregisterCommand(&m_mouseRotate);
	//inputManager.unregisterCommand(&m_resetCamera);

}


} // namespace infinity 